Mise à jour le 17/11/2021
Immutable MVC en PHP version 2019

Immutable MVC en PHP version 2019


Ceci est une proposition de traduction de la page Immutable MVC: MVC In PHP 2019 Edition (https://r.je/immutable-mvc-in-php) de Tom Butler, que j'estime être très doué.
A noter que je n'ai pas trouvé quelle était la licence sur le contenu de son article, il est bien entendu que cette page sera supprimée si la copie de l'article original est interdite.

-- Début de la traduction --

1. MVC Revisité

Les articles les plus populaires de ce site Web concernent le MVC, dont le plus ancien a maintenant près de dix ans. Beaucoup de choses ont changé au cours de cette période, et ma propre expérience s'est également enrichie. Ma précédente série d'articles sur les "accidents vasculaires cérébraux" s'est en quelque sorte éteinte parce que je voulais revenir en arrière et peaufiner les exemples des articles précédents.

Le PHP a beaucoup changé depuis que j'ai écrit ces articles. Je vais prendre un nouveau départ et donner des exemples de code plus propres, plus complets et plus modernes.

Neuf ans se sont écoulés depuis que j'ai écrit le premier article sur les MVC ici et j'ai quelques observations à faire à ce sujet en regardant en arrière :

L'écosystème du PHP n'a pas changé. Les gens confondent toujours l'approche "contrôleur au lieu de médiateur" et MVC. Si la situation a empiré parce que les cadres populaires sont maintenant si bien intégrés, essayer de faire quelque chose de différent semble tout simplement mal.
Les points que j'ai soulevés sont toujours valables. Donner à la vue l'accès au modèle présente des avantages significatifs que je ne répéterai pas ici. Jetez un coup d'œil à mon précédent article si vous êtes intéressé.
Les exemples de code que j'ai donnés ne sont pas assez clairs ou complets. J'ai passé plus de temps à me concentrer sur les concepts qu'à donner des exemples de code. Je vais rectifier cela ici.
En plus d'écrire des exemples plus complets, il est temps de faire une mise à jour avec les nouvelles fonctionnalités de PHP et les tendances de programmation comme l'immutabilité. Je vais vous montrer comment écrire une structure MVC complètement immuable. Ensuite, je vous montrerai des contrôleurs réutilisables et un système de routage.

Outre l'utilisation de nouvelles fonctionnalités de PHP telles que l'indication du type de retour (ndlr, PHP 7.0), les deux principaux changements que j'ai apportés à mon style de codage sont l'immutabilité et le fait de privilégier les arguments par rapport aux constructeurs ayant des propriétés connexes.

2. Hello World

Voici une démonstration du trinome MVC en immutable à travers le fichier mvc.php dont voici le contenu :

class Model
{
    public $text;
    
    public function __construct() 
    {
        $this->text = 'Hello world!';
    }
}

class View
{
    private $model;

    public function __construct(Model $model) 
    {
        $this->model = $model;
    }

    public function output()
    {
        return '<a href="mvc.php?action=textclicked">' . $this->model->text . '</a>';
    }
}

class Controller
{
    private $model;

    public function __construct(Model $model)
    {
        $this->model = $model;
    }

    public function textClicked()
    {
        $this->model->text = 'Text Updated';
    }
}

$model = new Model();

// It is important that the controller and the view share the model.
$controller = new Controller($model);

$view = new View($model);

if (isset($_GET['action'])) $controller->{$_GET['action']}();
echo $view->output();


3. Le modèle

Dans cet exemple, le modèle est mutable mais les autres composants ne le sont pas. Tout d'abord, rendons le modèle immuable :

class Model
{
    private $text;

    public function __construct($text = 'Hello World')
    {
        $this->text = $text;
    }

    public function getText()
    {
        return $this->text;
    }
    
    public function setText($text)
    {
        return new Model($text);
    }
}

Il n'est plus possible de modifier l'état du modèle une fois qu'il a été instancié. L'appel de la méthode setText crée une nouvelle instance. Tout endroit où l'instance originale est référencée ne verra pas de changement dans l'état du modèle. Le contrôleur et la vue devront être mis à jour pour utiliser cette nouvelle classe de modèle.

Auparavant, le modèle et le contrôleur partageaient une instance de modèle. Le contrôleur modifiait l'état du modèle et la vue lisait l'état de l'instance de modèle. Maintenant que le modèle est immuable, nous ne pouvons plus compter sur le fait que la vue et le contrôleur partagent la même instance de modèle. Au lieu de cela, l'action du contrôleur retournera une instance de modèle qui sera ensuite transmise à la vue.

4. Le contrôleur

Au lieu de mettre à jour l'état d'une instance de modèle existante et mutable, le contrôleur renvoie une nouvelle instance de modèle après avoir effectué ses modifications :

class Controller
{
    public function textClicked(Model $model): Model
    {
        return $model->setText('Text Clicked');
    }
}


Plutôt que de m'appuyer sur les constructeurs et les propriétés, j'ai choisi d'utiliser des arguments pour faire passer le modèle qui va être mis à jour. L'action du contrôleur reçoit maintenant une instance de modèle immuable et renvoie une nouvelle instance avec les modifications nécessaires.

Il est à noter que cela ne fait pas partie de MVC, l'utilisation d'arguments de constructeur avec des propriétés liées ou d'arguments à l'action de contrôleur ont le même effet. Mais en évitant les constructeurs, il n'est plus nécessaire de conserver le modèle comme une propriété et le contrôleur est considérablement simplifié. Moins de code pour faire le même travail est toujours une bonne chose.

5. La vue

La vue nécessite peu de modification pour arriver au même résultat (plus besoin de l'attribut publique).

class View
{
    public function output(Model $model)
    {
        return '<a href="mvc.php?action=textClicked">' . $model->getText() . '</a>';
    }
}

L'avantage de faire passer le modèle en argument est que une seule instance de View permet d'afficher autant de modèles que l'on souhaite.

6. Mise en place du trinome

Il ne reste plus qu'à instancier tout ce petit monde, plus besoin de passer le modèle aux constructeurs de la View et du Controller.

<?php
$model = new Model();
$controller = new Controller();
$view = new View();

if (isset($_GET['action']))
{
    $model = $controller->{$_GET['action']}($model);
}

echo $view->output($model);


Dans cette version immuable, le modèle est passé au contrôleur qui construit une nouvelle instance du modèle qui est ensuite passé à la vue.

7. Conclusion

Cette implémentation immuable de MVC présente certains avantages par rapport à la version mutable :

L'état est mieux géré de sorte que l'application ne souffre pas d'une action à distance où le changement d'un objet à un endroit (dans le contrôleur) provoque ensuite des changements dans un composant apparemment sans rapport (la vue).
Il y a moins d'État dans l'ensemble. Il n'y a plus de références aux différents objets en plusieurs endroits. Le contrôleur et la vue n'ont plus de référence au modèle, on leur donne une instance avec laquelle travailler au moment où ils en ont besoin, pas avant.

-- Fin de la traduction --

Bien évidemment, ce code ne doit pas se retrouver de cette façon dans votre application car le paramètre HTTP action doit être vérifié (ie : on contrôle que l'utilisateur a le droit ou non de faire l'action).

8. Vue d'artiste

Attention : le schéma suivant ne représente pas vraiment la beauté conceptuelle derrière le MVC.